#include "xcom_process.h"
#include "xcom_node.h"

namespace protocol {
XComProcess::XComProcess(const std::shared_ptr<protocol::XComNode> &xcomNode,
	const std::string &addr)
	: xcomNode_(xcomNode)
	, dataItem_(xcomNode->GetName(), xcomNode->GetTemplate())
{
	dataItem_.SetVar("addr", libxcom::OpValue(addr));
}

XComProcess::~XComProcess() {}

bool XComProcess::IsReadFlow(const std::string &funcId)
{
	if (xcomNode_ == nullptr) {
		return false;
	}
	if (!xcomNode_->HasFuncId(funcId)) {
		HTELINK_LOG_ERR("not find funcId %s", funcId);
		return false;
	}
	const FuncParam_t &funcParam = xcomNode_->GetFuncParam(funcId);
	if (funcParam.flow.find("read") == funcParam.flow.npos) {
		return false;
	}
	return true;
}

bool XComProcess::Process(const std::string &funcId, XComSend sendFunc,
	const std::vector<libxcom::OpValue> &params, float ratio)
{
	if (xcomNode_ == nullptr) {
		return false;
	}
	if (dataItem_.HasVar(funcId)) {
		return true;
	}

	if (!xcomNode_->HasFuncId(funcId)) {
		HTELINK_LOG_ERR("not find funcId %s", funcId);
		return false;
	}

	const FuncParam_t &funcParam = xcomNode_->GetFuncParam(funcId);
	Flow_t flow = xcomNode_->GetFlow(funcParam.flow);
	dataItem_.SetDataExpr(funcParam.resultExpr, ratio);

	for (auto &var : funcParam.vars) {
		//  second 需要先转换成OpValue
		dataItem_.SetVar(var.first, var.second);
	}

	dataItem_.EmptyParam();
	for (auto &opValue : params) {
		dataItem_.PushParam(opValue);
	}

	if (dataItem_.HasVar(funcParam.flow)) {
		dataItem_.SetVar(funcId, dataItem_.Result());
		return true;
	}
	libxcom::OpValue cmd;
	for (auto &proc : flow.procList) {
		if (proc.call == "send") {
			// 指令序列化, 绑定send函数
			cmd = dataItem_.GenerateCmd(proc.expr);
			if (cmd.IsEmpty()) {
				HTELINK_LOG_ERR(
					"cmd gen failed, %s", proc.expr->GetExprString());
				return false;
			}
		} else if (proc.call == "recv") {
			dataItem_.ParseRecvCmd(proc.expr);
			auto func = [&](uint8_t *buf, int32_t len) -> libxcom::RECV_RESULT {
				return dataItem_.ProcessRealRecv(buf, len);
			};
			if (!sendFunc(cmd.GenCmd(), func)) {
				HTELINK_LOG_ERR("process %s send failed", proc.call);
				return false;
			}
		} else {
			HTELINK_LOG_ERR("Not support this process, %s", proc.call.c_str());
			return false;
		}
	}
	auto result = dataItem_.Result();
	if (result.IsEmpty()) {
		HTELINK_LOG_ERR("get result failed");
		return false;
	}
	dataItem_.SetVar(funcId, std::move(result));
	return true;
}
libxcom::OpValue XComProcess::GetResult(const std::string &var)
{
	return dataItem_.GetVar(var);
}
} // namespace protocol